#include "src\precompiled.h"
#include "src\file_system.h"

template<> file_system *singleton<file_system>::m_singleton = 0;

file_system::file_system() { }

file_system::file_system(const std::string &config) { assert(0); /* not implemented */ }

file_system::~file_system() { }

std::string file_system::parse_disk_letter(const std::string &p) const
{
	if(p.empty())
		return "";
	std::string tmp = p;
	fix_slashes(tmp);
	size_t len = tmp.find_first_of(":");
	if(len == std::string::npos)
		return "";
	return tmp.substr(0, len + 1);
}

std::string file_system::parse_path(const std::string &p) const
{
	if(p.empty())
		return "";
	std::string tmp = p;
	fix_slashes(tmp);
	size_t len = tmp.find_last_of("/");
	if(len == std::string::npos)
		return "";
	return tmp.substr(0, ++len);
}

std::string file_system::parse_filename(const std::string &p) const
{
	if(p.empty())
		return "";
	std::string tmp = p;
	fix_slashes(tmp);
	size_t off = tmp.find_last_of("/");
	if(off == std::string::npos)
		off = 0;
	else
		off++;
	size_t len = tmp.length() - off;
	return tmp.substr(off, len);
}

std::string file_system::parse_name(const std::string &p) const
{
	if(p.empty())
		return "";
	std::string tmp = p;
	fix_slashes(tmp);
	size_t off = tmp.find_last_of("/");
	if(off == std::string::npos)
		off = 0;
	else
		off++;
	size_t len = tmp.find_last_of(".");
	if(len == std::string::npos)
		len = tmp.length() - off;
	else
		len -= off;
	return tmp.substr(off, len);
}

std::string file_system::parse_suffix(const std::string &p) const
{
	if(p.empty())
		return "";
	std::string tmp = p;
	fix_slashes(tmp);
	size_t off = tmp.find_last_of(".");
	if(off == std::string::npos)
		return "";
	size_t len = tmp.length() - off;
	return tmp.substr(off, len);
}

void file_system::set_path(const char *alias, const std::string &p)
{
	std::string temp = p;
	fix_slashes(temp);
	create_dir(temp);
	m_aliases[alias] = temp;
}

std::string file_system::get_path(const char *alias) const
{
	alias_map::const_iterator it = m_aliases.find(alias);
	if(it == m_aliases.end())
		return "";
	return it->second;
}

void file_system::fix_slashes(std::string &val) const
{
	std::string::iterator it;
	for(it = val.begin(); it != val.end(); it++) {
		if(*it == '\\') {
			*it = '/';
		}
	}
	for(it = val.begin(); it != val.end(); it++) {
		if(*it == '/') {
			while(it != val.end() - 1 && *(it + 1) == '/')
				val.erase(it + 1);
		}
	}
}

void file_system::create_dir(const std::string &p) const
{
	if(path_exists(p))
		return;
	std::string dir = parse_disk_letter(p);
	std::string temp = p;
	if(dir.empty()) {
		temp = get_current_dir() + "/" + p;
		dir = parse_disk_letter(temp);
	}
	string_list parts = split_path(temp);
	string_list::iterator it;
	for(it = parts.begin(); it != parts.end(); it++) {
		dir += std::string("/") + *it;
		if(!path_exists(dir))
			CreateDirectory(dir.c_str(), NULL);
	}
}

void file_system::copy_file(const std::string &source, const std::string &target) const
{
	std::string dir = parse_path(target);
	create_dir(dir);
	CopyFile(source.c_str(), target.c_str(), FALSE);
}

bool file_system::path_exists(const std::string &p) const
{
	WIN32_FIND_DATA fd;
	HANDLE h = FindFirstFile(p.c_str(), &fd);
	if(h != INVALID_HANDLE_VALUE) {
		FindClose(h);
		return true;
	}
	return false;
}

string_list file_system::split_path(const std::string &p) const
{
	std::string temp = p;
	fix_slashes(temp);
	string_list result;
	size_t first = -1, last;
	do {
		first = temp.find_first_of('/', first + 1);
		if(first != std::string::npos && first != temp.length() - 1) {
			last = temp.find_first_of('/', first + 1);
			if(last == std::string::npos)
				last = temp.length();
			std::string part = temp.substr(first + 1, last - first - 1);
			result.push_back(part);
		}
	}
	while(first != std::string::npos);
	return result;
}

std::string file_system::get_current_dir() const
{
	TCHAR buffer[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, buffer);
	std::string temp(buffer);
	fix_slashes(temp);
	return temp;
}

void file_system::set_current_dir(const std::string &dir)
{
	std::string temp = dir;
	fix_slashes(temp);
	create_dir(temp);
	::SetCurrentDirectory(temp.c_str());
}